package Simulation;

import IA.*;
import java.util.ArrayList;
import java.util.Iterator;


/**
 *
 * @author Rob Leister rleist1@students.towson.edu
 */
public class KitchenSimulator implements ClockObserverInterface {

    private final int DEFAULT_COOK_CAPACITY = 5;
    private int CookCapacity; //number of items that can be simulataneously 'cooked' (decremented)
    private KitchenQueue kq;
    private ArrayList<KitchenWatcherInterface> Servers;
    private CookStrategy cs;
    private double TIME_REDUCTION_FACTOR = 0.5; //reduction factor if item type is already on grill

    public KitchenSimulator(KitchenQueue kq) {
        CookCapacity = DEFAULT_COOK_CAPACITY;
        this.kq = kq;
        cs = new ChronologicalCookStrategy(); //default
        Servers = new ArrayList<KitchenWatcherInterface>();
    }

    public void addWatcher(KitchenWatcherInterface server) {
        Servers.add(server);
    }

    public void removeWatcher(KitchenWatcherInterface server) {
        Servers.remove(server);
    }

    public Observable getObservableInstance() {
        return new Observable() {

            @Override
            public void AddObserver(Object Observer) {
                addWatcher((KitchenWatcherInterface) Observer);
            }

            @Override
            public void RemoveObserver(Object Observer) {
                removeWatcher((KitchenWatcherInterface) Observer);
            }
            
        };
    }
    
    @Override
    public void clockTick() {
        CookAll();
        if (kq.getNumCookingItems() < CookCapacity) {
            ArrayList<CookItem> ItemsToCook =
                    cs.getNextOrders(kq.getCookingItems(), kq.getQueueItems(), CookCapacity - kq.getNumCookingItems());
            for (CookItem i : ItemsToCook) {
                //if the item is already cooking, it gets a time reduction, else its standard time
                if (kq.ItemCooking(i.getName())) {
                    kq.startCookingItem(i, TIME_REDUCTION_FACTOR);
                } else {
                    kq.startCookingItem(i, 1.0);
                }
            }
        }
    }

    private void CookAll() {
        for (Iterator<CookItem> itr = kq.getCookingItemsIterator(); itr.hasNext();) {
            CookItem item = itr.next();
            if (item.Cook()) {
                //item is done cooking
                if (kq.finishCookingItem(item, itr)) {
                    //item is last for table, alert servers
                    System.out.println("food done for table " + item.getTableID());
                    AlertServers(item.getTableID());
                }
            }
        }
    }

    private void AlertServers(int TableID) {
        for (KitchenWatcherInterface s : Servers) {
            System.out.println("Alerting server for table " + TableID);
            s.OrderUp(TableID);
        }
    }

    public void setCookStrategy(CookStrategy cs) {
           this.cs = cs;
    }

    public double getTimeReductionFactor() {
        return TIME_REDUCTION_FACTOR;
    }

    public void setTimeReductionFactor(double factor) {
        TIME_REDUCTION_FACTOR = factor;
    }

    public int getGrillCapacity() {
        return CookCapacity;
    }

    public void setGrillCapacity(int c) {
        CookCapacity = c;
    }
}
